Skip to content

Conversation

@joshunrau
Copy link
Collaborator

@joshunrau joshunrau commented Nov 5, 2025

Summary by CodeRabbit

  • New Features

    • Added JWT-based authentication system with login endpoints
    • Implemented role-based access control (Admin, Group Manager, Standard)
    • Added login interface to playground application
  • Changes

    • Removed multiple pre-built instrument forms (PHQ-9, GAD-7, AUDIT_C, CUDIT_R, and others)
    • Migrated database layer to Prisma ORM with MongoDB support
    • Authentication now required for token-based API access

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Major authentication system overhaul with CASL-based authorization and JWT strategies. Introduces new auth module, ability factory, JWT guards, and decorators. Migrates types (AppAbility, RouteAccess) from external package to local implementations. Refactors Prisma integration with new factory and MongoDB support. Removes instrument library DTOs and several form definitions.

Changes

Cohort / File(s) Summary
Authentication Implementation
apps/api/src/auth/auth.types.ts, apps/api/src/auth/auth.service.ts, apps/api/src/auth/auth.controller.ts, apps/api/src/auth/auth.module.ts, apps/api/src/auth/ability.factory.ts, apps/api/src/auth/ability.utils.ts, apps/api/src/auth/strategies/jwt.strategy.ts
New CASL-based authorization types and JWT authentication; added JwtStrategy, AbilityFactory service, auth controller with login/token endpoints, auth module with JWT/Passport configuration, utility functions for ability/query integration.
Authorization Guards & Decorators
apps/api/src/auth/guards/jwt-auth.guard.ts, apps/api/src/core/decorators/route-access.decorator.ts
New JWT auth guard with route-level access control; route access decorator supporting public/protected routes with action/subject validation.
Auth Tests
apps/api/src/auth/__tests__/ability.utils.test.ts, apps/api/src/auth/guards/__tests__/jwt-auth.guard.spec.ts
Unit tests for ability utilities and JWT guard behavior across public/protected routes.
Prisma Integration Refactor
apps/api/src/core/prisma.ts, apps/api/src/core/types.ts, apps/api/src/core/schemas/env.schema.ts, apps/api/src/core/schemas/mongo-stats.schema.ts
New PrismaModuleOptionsFactory with MongoDB in-memory/external connection handling; RuntimePrismaClient type; MongoDB environment schema; MongoStats schema for DB operations.
Module Configuration
apps/api/libnest.config.ts, apps/api/main.ts
Module augmentation for UserTypes (Env, PrismaClient, RequestUser); replaced ConfiguredAuthModule with AuthModule; registered PrismaModule async.
Service Type Updates
apps/api/src/assignments/assignments.service.ts, apps/api/src/groups/groups.service.ts, apps/api/src/instruments/instruments.service.ts, apps/api/src/instrument-records/instrument-records.service.ts, apps/api/src/sessions/sessions.service.ts, apps/api/src/subjects/subjects.service.ts, apps/api/src/users/users.service.ts
Moved accessibleQuery imports to local path; updated Prisma client types from ExtendedPrismaClient to RuntimePrismaClient; refactored constructor signatures.
Controller Import Paths
apps/api/src/assignments/assignments.controller.ts, apps/api/src/gateway/gateway.controller.ts, apps/api/src/groups/groups.controller.ts, apps/api/src/instruments/instruments.controller.ts, apps/api/src/sessions/sessions.controller.ts, apps/api/src/setup/setup.controller.ts, apps/api/src/subjects/subjects.controller.ts, apps/api/src/users/users.controller.ts, apps/api/src/summary/summary.controller.ts
Updated imports: AppAbility from @/auth/auth.types, RouteAccess from @/core/decorators/route-access.decorator.
DTO Removal & Schema Migration
apps/api/src/instrument-records/dto/create-instrument-record.dto.ts, apps/api/src/instrument-records/dto/update-instrument-record.dto.ts, apps/api/src/instrument-records/dto/upload-instrument-record.dto.ts, apps/api/src/instrument-records/instrument-records.controller.ts
Removed DTOs; replaced with schema types ($CreateInstrumentRecordData, $UpdateInstrumentRecordData, $UploadInstrumentRecordsData) from @opendatacapture/schemas.
Demo & Setup Services
apps/api/src/demo/demo.service.ts, apps/api/src/setup/setup.service.ts
Migrated to RuntimePrismaClient; added MongoDB stats/database drop helpers; removed PHQ_9 instrument initialization.
Global Type Augmentation
apps/api/src/typings/global.d.ts
Added Express.User augmentation extending RequestUser.
Package Dependency Updates
apps/api/package.json, pnpm-workspace.yaml
Added @casl/\, @nestjs/jwt, @nestjs/passport, passport-\ packages; updated @douglasneuroinformatics/libnest to ^8.0.1; added mongodb-memory-server for tests; added neverthrow to catalog.
Schema Type Exports
packages/schemas/src/auth/auth.ts, packages/schemas/src/instrument-records/instrument-records.ts
Renamed LoginCredentials to $LoginCredentials; added non-empty string validation; added optional additionalPermissions to TokenPayload; exposed schema types for instrument record operations.
Instrument Library Cleanup
packages/instrument-library/src/forms/ADHD_ASRS_1.1/index.ts, packages/instrument-library/src/forms/AUDIT_C/index.ts, packages/instrument-library/src/forms/CUDIT_R/index.ts, packages/instrument-library/src/forms/FAGERSTRÖM_NICOTINE_DEPENDENCE/index.ts, packages/instrument-library/src/forms/GAD_7/index.ts, packages/instrument-library/src/forms/OLDER_AMERICANS_RESOURCES_AND_SERVICES/index.ts, packages/instrument-library/src/forms/PHQ_9/index.ts, packages/instrument-library/src/forms/STARKSTEIN_APATHY_SCALE/index.ts, packages/instrument-library/src/forms/TEN_ITEM_PERSONALITY_INVENTORY/index.ts
Removed nine instrument form definitions with their validation, scoring logic, and multilingual metadata.
Runtime Core Updates
packages/runtime-core/src/define.ts, packages/runtime-core/src/types/instrument.series.ts
Added defineSeriesInstrument helper; updated SeriesInstrument documentation tag from @beta to @public.
Web App Auth Updates
apps/web/src/routes/auth/login.tsx, apps/web/src/components/LoginForm/LoginForm.tsx, apps/web/src/components/DemoBanner/DemoBanner.tsx
Updated LoginCredentials to $LoginCredentials across login components and callbacks.
Playground App Auth Integration
apps/playground/src/store/slices/auth.slice.ts, apps/playground/src/store/types.ts, apps/playground/src/store/index.ts, apps/playground/src/components/Header/ActionsDropdown/ActionsDropdown.tsx, apps/playground/src/components/Header/ActionsDropdown/LoginDialog.tsx, apps/playground/src/components/Header/ActionsDropdown/UploadBundleDialog.tsx, apps/playground/package.json
Added auth slice with token management; integrated JWT decode; new LoginDialog component; updated UploadBundleDialog with auth callbacks; added jwt-decode and neverthrow dependencies.
Test Infrastructure
testing/e2e/src/global/global.setup.spec.ts, testing/e2e/src/helpers/types.ts, testing/e2e/playwright.config.ts, testing/k6/src/index.ts
Removed GLOBAL_SETUP_COMPLETE env var; updated LoginCredentials to $LoginCredentials; added BrowserTarget type; configured server output streaming for CI.
CI Workflow & Version
.github/workflows/ci.yaml, runtime/v1/package.json, package.json
Removed Docker MongoDB setup step (using in-memory MongoDB now); bumped runtime version 1.8.7→1.8.8; bumped main version 1.11.2→1.12.0.
Removed Legacy Auth Module
apps/api/src/vendor/configured.auth.module.ts
Deleted ConfiguredAuthModule with forRootAsync factory and role-based ability definitions (functionality replaced by new auth infrastructure).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthController
    participant AuthService
    participant AbilityFactory
    participant JwtService
    participant UsersService

    Client->>AuthController: POST /auth/login (credentials)
    AuthController->>AuthService: login(credentials)
    AuthService->>UsersService: findByUsername(username, includeHashedPassword)
    UsersService-->>AuthService: user + hashedPassword
    AuthService->>AuthService: verifyPassword(credentials.password, user.hashedPassword)
    AuthService->>AbilityFactory: createForPayload(tokenPayload)
    AbilityFactory-->>AuthService: AppAbility
    AuthService->>JwtService: sign({ ...tokenPayload, permissions })
    JwtService-->>AuthService: accessToken
    AuthService-->>AuthController: { accessToken }
    AuthController-->>Client: 200 { accessToken }

    Client->>+AuthController: GET /resource (Bearer token)
    AuthController->>JwtAuthGuard: canActivate(context)
    JwtAuthGuard->>JwtStrategy: validate(payload)
    JwtStrategy->>AbilityFactory: createForPermissions(payload.permissions)
    AbilityFactory-->>JwtStrategy: AppAbility
    JwtStrategy-->>JwtAuthGuard: { ...payload, ability }
    JwtAuthGuard->>JwtAuthGuard: check route access + ability permissions
    JwtAuthGuard-->>AuthController: true (authorized) / false (denied)
    alt Authorized
        AuthController-->>Client: 200 resource
    else Unauthorized
        AuthController-->>Client: 403 Forbidden
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Auth system introduction: New JWT strategy, ability factory, guards, and decorators require careful validation of permission logic, token generation, and request user context injection across multiple files.
  • Service refactoring patterns: While many changes follow consistent import/type migration patterns, each service update needs verification that the new Prisma client type maintains query semantics.
  • Prisma factory complexity: PrismaModuleOptionsFactory with conditional in-memory/external MongoDB connections, dynamic imports, and lifecycle management (onApplicationShutdown) warrants close inspection.
  • Cross-cutting import changes: Dozens of files updated with import path migrations to local auth/decorator modules—verify no circular dependencies or missed imports.
  • Instrument removal scope: Nine instrument definitions removed—confirm no active references remain in tests, exports, or dynamically loaded registries.
  • Potential attention areas:
    • apps/api/src/auth/auth.service.ts — password verification, token payload construction, permission inclusion logic
    • apps/api/src/core/prisma.ts — MongoDB connection factory, in-memory replica set initialization, datasource URL building
    • apps/api/src/auth/guards/jwt-auth.guard.ts — route access metadata resolution, ability permission checking
    • packages/instrument-library/ — confirm removed instruments are not re-exported or dynamically loaded elsewhere

Possibly related PRs

  • update libnest to add auto documentation #1110: Updates @douglasneuroinformatics/libnest dependency version, same as this PR's dependency migration strategy.
  • v1.9.3 #1112: Modifies @casl/ability and @casl/prisma dependencies and API environment schema typings, overlapping authorization infrastructure changes.
  • feat: support zod v4 schemas #1157: Modifies module augmentation in libnest.config.ts for UserTypes declarations (UserConfig, RequestUser, Env, PrismaClient), directly related type configuration.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'update libnest to v8' accurately reflects the main change: updating the @douglasneuroinformatics/libnest dependency from v7.3.3 to v8.0.1 and extracting libnest-provided functionality into local project paths.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57ebc73 and edc56f6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/api/package.json (3 hunks)
  • apps/api/src/instrument-records/instrument-records.controller.ts (3 hunks)
  • apps/playground/package.json (1 hunks)
  • apps/playground/src/components/Header/ActionsDropdown/ActionsDropdown.tsx (4 hunks)
  • apps/playground/src/components/Header/ActionsDropdown/LoginDialog.tsx (1 hunks)
  • apps/playground/src/components/Header/ActionsDropdown/UploadBundleDialog.tsx (3 hunks)
  • apps/playground/src/store/index.ts (4 hunks)
  • apps/playground/src/store/slices/auth.slice.ts (1 hunks)
  • apps/playground/src/store/types.ts (3 hunks)
  • package.json (2 hunks)
  • pnpm-workspace.yaml (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6dcaae3 and 22a3712.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (52)
  • apps/api/libnest.config.ts (1 hunks)
  • apps/api/package.json (3 hunks)
  • apps/api/src/assignments/assignments.controller.ts (1 hunks)
  • apps/api/src/assignments/assignments.service.ts (1 hunks)
  • apps/api/src/auth/__tests__/ability.utils.test.ts (1 hunks)
  • apps/api/src/auth/ability.factory.ts (1 hunks)
  • apps/api/src/auth/ability.utils.ts (1 hunks)
  • apps/api/src/auth/auth.controller.ts (1 hunks)
  • apps/api/src/auth/auth.module.ts (1 hunks)
  • apps/api/src/auth/auth.service.ts (1 hunks)
  • apps/api/src/auth/auth.types.ts (1 hunks)
  • apps/api/src/auth/guards/__tests__/jwt-auth.guard.spec.ts (1 hunks)
  • apps/api/src/auth/guards/jwt-auth.guard.ts (1 hunks)
  • apps/api/src/auth/strategies/jwt.strategy.ts (1 hunks)
  • apps/api/src/core/decorators/route-access.decorator.ts (1 hunks)
  • apps/api/src/core/prisma.ts (1 hunks)
  • apps/api/src/core/schemas/env.schema.ts (1 hunks)
  • apps/api/src/core/schemas/mongo-stats.schema.ts (1 hunks)
  • apps/api/src/core/types.ts (1 hunks)
  • apps/api/src/demo/demo.service.ts (5 hunks)
  • apps/api/src/gateway/gateway.controller.ts (1 hunks)
  • apps/api/src/groups/groups.controller.ts (1 hunks)
  • apps/api/src/groups/groups.service.ts (1 hunks)
  • apps/api/src/instrument-records/dto/create-instrument-record.dto.ts (0 hunks)
  • apps/api/src/instrument-records/dto/update-instrument-record.dto.ts (0 hunks)
  • apps/api/src/instrument-records/dto/upload-instrument-record.dto.ts (0 hunks)
  • apps/api/src/instrument-records/instrument-records.controller.ts (3 hunks)
  • apps/api/src/instrument-records/instrument-records.service.ts (2 hunks)
  • apps/api/src/instruments/instruments.controller.ts (1 hunks)
  • apps/api/src/instruments/instruments.service.ts (2 hunks)
  • apps/api/src/main.ts (2 hunks)
  • apps/api/src/sessions/sessions.controller.ts (1 hunks)
  • apps/api/src/sessions/sessions.service.ts (1 hunks)
  • apps/api/src/setup/setup.controller.ts (1 hunks)
  • apps/api/src/setup/setup.service.ts (4 hunks)
  • apps/api/src/subjects/__tests__/subjects.service.spec.ts (1 hunks)
  • apps/api/src/subjects/subjects.controller.ts (1 hunks)
  • apps/api/src/subjects/subjects.service.ts (1 hunks)
  • apps/api/src/summary/summary.controller.ts (1 hunks)
  • apps/api/src/typings/global.d.ts (1 hunks)
  • apps/api/src/users/users.controller.ts (1 hunks)
  • apps/api/src/users/users.service.ts (2 hunks)
  • apps/api/src/vendor/configured.auth.module.ts (0 hunks)
  • apps/web/src/components/DemoBanner/DemoBanner.tsx (1 hunks)
  • apps/web/src/components/LoginForm/LoginForm.tsx (1 hunks)
  • apps/web/src/routes/auth/login.tsx (3 hunks)
  • package.json (1 hunks)
  • packages/schemas/src/auth/auth.ts (1 hunks)
  • packages/schemas/src/instrument-records/instrument-records.ts (2 hunks)
  • testing/e2e/src/global/global.setup.spec.ts (1 hunks)
  • testing/e2e/src/helpers/types.ts (1 hunks)
  • testing/k6/src/index.ts (2 hunks)
💤 Files with no reviewable changes (4)
  • apps/api/src/instrument-records/dto/upload-instrument-record.dto.ts
  • apps/api/src/vendor/configured.auth.module.ts
  • apps/api/src/instrument-records/dto/update-instrument-record.dto.ts
  • apps/api/src/instrument-records/dto/create-instrument-record.dto.ts
🧰 Additional context used
🧬 Code graph analysis (24)
apps/api/src/auth/strategies/jwt.strategy.ts (4)
apps/api/src/auth/ability.factory.ts (1)
  • Injectable (11-63)
apps/api/src/auth/auth.service.ts (1)
  • Injectable (11-60)
apps/api/src/auth/guards/jwt-auth.guard.ts (1)
  • Injectable (12-56)
packages/schemas/src/auth/auth.ts (1)
  • TokenPayload (17-25)
apps/api/src/auth/auth.service.ts (4)
apps/api/src/auth/ability.factory.ts (1)
  • Injectable (11-63)
apps/api/src/auth/strategies/jwt.strategy.ts (1)
  • Injectable (11-28)
apps/api/src/users/users.service.ts (1)
  • Injectable (13-167)
packages/schemas/src/auth/auth.ts (3)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
  • TokenPayload (17-25)
apps/api/src/subjects/__tests__/subjects.service.spec.ts (1)
apps/api/src/core/prisma.ts (1)
  • RuntimePrismaClient (67-69)
apps/api/src/core/prisma.ts (5)
apps/api/src/sessions/sessions.service.ts (1)
  • Injectable (15-121)
apps/api/src/demo/demo.service.ts (1)
  • Injectable (35-173)
apps/api/src/setup/setup.service.ts (1)
  • Injectable (16-95)
apps/api/src/subjects/subjects.service.ts (1)
  • Injectable (12-146)
apps/api/libnest.config.ts (1)
  • PrismaClient (18-18)
apps/api/src/auth/auth.controller.ts (3)
apps/api/src/assignments/assignments.controller.ts (1)
  • Controller (13-37)
apps/api/src/core/decorators/route-access.decorator.ts (1)
  • RouteAccess (18-20)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/web/src/routes/auth/login.tsx (1)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/web/src/components/LoginForm/LoginForm.tsx (1)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/api/src/auth/ability.factory.ts (4)
apps/api/src/auth/auth.service.ts (1)
  • Injectable (11-60)
apps/api/src/auth/strategies/jwt.strategy.ts (1)
  • Injectable (11-28)
packages/schemas/src/auth/auth.ts (1)
  • TokenPayload (17-25)
apps/api/src/auth/ability.utils.ts (2)
  • detectAppSubject (13-18)
  • createAppAbility (20-24)
apps/api/libnest.config.ts (2)
apps/api/src/core/schemas/env.schema.ts (2)
  • $Env (5-5)
  • $Env (6-35)
apps/api/src/core/prisma.ts (1)
  • RuntimePrismaClient (67-69)
testing/e2e/src/global/global.setup.spec.ts (4)
testing/e2e/src/helpers/fixtures.ts (1)
  • test (11-17)
testing/e2e/src/pages/__root.page.ts (1)
  • expect (12-14)
testing/e2e/src/helpers/data.ts (1)
  • initAppOptions (3-14)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/api/src/auth/guards/jwt-auth.guard.ts (3)
apps/api/src/auth/ability.factory.ts (1)
  • Injectable (11-63)
apps/api/src/auth/strategies/jwt.strategy.ts (1)
  • Injectable (11-28)
apps/api/src/core/decorators/route-access.decorator.ts (2)
  • RouteAccessType (16-16)
  • ROUTE_ACCESS_METADATA_KEY (22-22)
testing/k6/src/index.ts (1)
packages/schemas/src/auth/auth.ts (3)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
  • AuthPayload (7-9)
packages/schemas/src/auth/auth.ts (1)
packages/schemas/src/core/core.ts (1)
  • Permissions (33-33)
apps/web/src/components/DemoBanner/DemoBanner.tsx (1)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/api/src/typings/global.d.ts (2)
packages/schemas/src/auth/auth.ts (1)
  • TokenPayload (17-25)
apps/api/src/auth/auth.types.ts (1)
  • AppAbility (23-23)
apps/api/src/subjects/subjects.service.ts (1)
apps/api/src/core/prisma.ts (1)
  • RuntimePrismaClient (67-69)
apps/api/src/auth/__tests__/ability.utils.test.ts (1)
apps/api/src/auth/ability.utils.ts (1)
  • accessibleQuery (26-35)
apps/api/src/auth/ability.utils.ts (2)
apps/api/src/core/prisma.ts (1)
  • PrismaModelWhereInputMap (71-77)
apps/api/src/auth/auth.types.ts (4)
  • Permission (23-23)
  • AppAbility (23-23)
  • AppAbilities (23-23)
  • AppAction (23-23)
apps/api/src/users/users.service.ts (1)
apps/api/src/core/types.ts (1)
  • EntityOperationOptions (3-5)
apps/api/src/instrument-records/instrument-records.controller.ts (2)
packages/schemas/src/instrument-records/instrument-records.ts (6)
  • $CreateInstrumentRecordData (9-9)
  • $CreateInstrumentRecordData (10-18)
  • $UploadInstrumentRecordsData (25-25)
  • $UploadInstrumentRecordsData (26-36)
  • $UpdateInstrumentRecordData (20-20)
  • $UpdateInstrumentRecordData (21-23)
apps/api/src/core/decorators/route-access.decorator.ts (1)
  • RouteAccess (18-20)
apps/api/src/demo/demo.service.ts (2)
apps/api/src/core/prisma.ts (1)
  • RuntimePrismaClient (67-69)
apps/api/src/core/schemas/mongo-stats.schema.ts (2)
  • $MongoStats (3-3)
  • $MongoStats (4-8)
apps/api/src/auth/guards/__tests__/jwt-auth.guard.spec.ts (3)
apps/api/src/auth/ability.factory.ts (1)
  • constructor (13-13)
apps/api/src/auth/guards/jwt-auth.guard.ts (1)
  • constructor (14-19)
apps/api/src/core/decorators/route-access.decorator.ts (1)
  • RouteAccessType (16-16)
apps/api/src/setup/setup.service.ts (2)
apps/api/src/core/prisma.ts (2)
  • Injectable (8-65)
  • RuntimePrismaClient (67-69)
apps/api/src/demo/demo.service.ts (1)
  • Injectable (35-173)
apps/api/src/sessions/sessions.service.ts (1)
apps/api/src/core/prisma.ts (2)
  • Injectable (8-65)
  • RuntimePrismaClient (67-69)
🪛 Biome (2.1.2)
apps/api/src/auth/guards/__tests__/jwt-auth.guard.spec.ts

[error] 17-17: Do not shadow the global "constructor" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🔇 Additional comments (63)
testing/e2e/src/helpers/types.ts (1)

13-14: LGTM!

The BrowserTarget type is well-defined and appropriate for e2e testing.

apps/api/src/core/types.ts (1)

1-1: LGTM - Import path updated to local auth types.

Consistent with the migration to local authentication/authorization modules.

apps/api/src/typings/global.d.ts (1)

1-15: LGTM - Express.User augmentation correctly structured.

The augmentation properly extends TokenPayload and adds the ability property for the new CASL-based authorization system.

apps/api/src/core/schemas/env.schema.ts (3)

2-2: LGTM - MongoDB environment integration added.

Correctly imports and integrates $MongoEnv for database configuration.


5-17: LGTM - Schema composition and type export.

The schema properly extends $BaseEnv with MongoDB shape and gateway-specific fields. Type export enables proper inference.


18-35: LGTM - Environment validation logic is correct.

Transform validates required fields per environment and sets the final API_PORT appropriately.

apps/api/libnest.config.ts (3)

1-3: LGTM - ESLint pragmas added for type augmentation.

Appropriate for the namespace augmentation pattern.


12-13: LGTM - Runtime types imported.

Correctly imports the runtime Prisma client and environment schema types.


15-20: Namespace augmentation pattern appears syntactically correct, but verify with internal libnest v8 documentation.

The module augmentation for UserTypes in apps/api/libnest.config.ts uses valid TypeScript syntax and is properly isolated to the config file. However, since libnest v8 documentation is not publicly available, confirm this pattern against your internal package documentation or contact the package maintainers to ensure it aligns with the intended v8 API.

apps/api/src/setup/setup.controller.ts (1)

5-5: LGTM - RouteAccess import migrated to local decorator.

Consistent with the refactor to use local authentication/authorization modules.

package.json (1)

81-85: LGTM - mongodb-memory-server build configuration added.

Correctly added to onlyBuiltDependencies to ensure native bindings are built properly.

apps/api/src/gateway/gateway.controller.ts (1)

5-5: LGTM - RouteAccess import migrated to local decorator.

Consistent with the refactor across all controllers.

apps/api/src/sessions/sessions.controller.ts (1)

5-5: LGTM - RouteAccess import migrated to local decorator.

Consistent with the refactor across all controllers.

apps/api/src/users/users.controller.ts (1)

1-7: Import refactoring looks good.

The migration from libnest to local auth types and decorators is clean. Controller logic remains unchanged.

apps/api/src/auth/__tests__/ability.utils.test.ts (1)

1-24: Test coverage is appropriate.

The test cases correctly validate both branches of accessibleQuery (undefined and defined ability). Mock setup is sound.

apps/api/src/auth/auth.controller.ts (1)

1-20: Login endpoint implementation is correct.

Public access, proper schema validation, and appropriate HTTP status code for the login operation.

packages/schemas/src/instrument-records/instrument-records.ts (1)

20-23: New update schema added.

The union of record and array for data field provides flexibility. Note that z.any() bypasses type safety—this appears intentional for dynamic instrument data but reduces compile-time guarantees.

apps/api/src/core/schemas/mongo-stats.schema.ts (1)

1-8: MongoStats schema is well-defined.

Simple and appropriate typing for MongoDB statistics.

packages/schemas/src/auth/auth.ts (1)

11-18: Auth schema updates are appropriate.

The type-first export pattern is consistent. Adding optional additionalPermissions maintains backward compatibility while enabling permission augmentation.

apps/api/src/instruments/instruments.service.ts (1)

1-28: Import migration completed correctly.

Moving accessibleQuery to local utilities aligns with the architecture changes. Service logic remains unchanged.

apps/api/src/instruments/instruments.controller.ts (1)

1-9: Import refactoring is consistent.

The migration to local auth types and decorators matches the pattern across other controllers.

apps/api/src/assignments/assignments.controller.ts (1)

1-7: LGTM - Clean import refactoring.

The import sources have been correctly updated to use local implementations of RouteAccess and AppAbility while maintaining CurrentUser from libnest. The changes align with the PR's goal of moving auth/authorization logic to local modules.

apps/api/src/summary/summary.controller.ts (1)

1-6: LGTM - Consistent import refactoring.

Import updates match the pattern seen across controllers, moving to local auth types while preserving the multi-entity authorization logic in the RouteAccess decorator.

apps/web/src/components/LoginForm/LoginForm.tsx (1)

5-9: LGTM - Type rename aligned with schema conventions.

The update from LoginCredentials to $LoginCredentials follows the Zod v4 schema naming pattern. The prop type is correctly updated with no behavioral changes.

apps/api/src/subjects/subjects.service.ts (1)

1-7: LGTM - Prisma client type migration.

The service correctly migrates from ExtendedPrismaClient to RuntimePrismaClient and moves accessibleQuery to the local auth utilities. The type is properly defined and all usages remain consistent.

apps/api/src/demo/demo.service.ts (2)

38-38: LGTM - Prisma client injection updated.

The constructor correctly injects RuntimePrismaClient via @InjectPrismaClient(), aligning with the new Prisma integration pattern.


158-172: LGTM - DB name derivation with proper error handling.

The new private methods correctly use $runCommandRaw to fetch MongoDB stats and parse them with the $MongoStats schema. Error handling appropriately throws InternalServerErrorException if parsing fails.

apps/web/src/routes/auth/login.tsx (3)

4-4: LGTM - Type import updated.

Correctly updated to use $LoginCredentials aligned with the schema changes.


15-15: LGTM - Function parameter type updated.

The loginRequest function parameter correctly uses the renamed $LoginCredentials type.


34-34: LGTM - Handler parameter type updated.

The handleLogin callback parameter correctly uses the renamed $LoginCredentials type.

testing/k6/src/index.ts (2)

2-2: LGTM - Test import updated.

The k6 load test correctly imports the renamed $LoginCredentials type.


54-54: LGTM - Generic type parameter updated.

The client.post call correctly uses $LoginCredentials as the generic parameter for the request payload type.

apps/api/src/main.ts (1)

1-6: Code changes are correct and properly configured.

Both PrismaModuleOptionsFactory (in apps/api/src/core/prisma.ts) and AuthModule (in apps/api/src/auth/auth.module.ts) are properly exported and correctly integrated. The PrismaModule.forRootAsync setup with the factory pattern is valid, and all imports reference the correct paths.

apps/api/src/sessions/sessions.service.ts (1)

1-3: LGTM!

The import reorganization and constructor updates are clean. The switch to RuntimePrismaClient and local accessibleQuery import align with the PR's auth system refactoring.

Also applies to: 9-10, 18-18, 22-22

apps/api/src/setup/setup.service.ts (2)

1-2: LGTM!

Import reorganization and constructor update to use RuntimePrismaClient with @InjectPrismaClient() decorator align with the PR's Prisma refactoring.

Also applies to: 4-9, 12-12, 19-19, 23-23


83-90: MongoDB command validation confirmed.

The implementation correctly validates the MongoDB dropDatabase response. According to MongoDB documentation, the dropDatabase command returns a result with an "ok" field that is 1 on success, which matches the check at line 85. The error handling is appropriate.

apps/api/src/auth/auth.service.ts (4)

1-18: LGTM!

Constructor dependencies are appropriate for JWT-based authentication with CASL authorization.


20-31: LGTM!

Converting NotFoundException to UnauthorizedException prevents user enumeration attacks. Good security practice.


32-35: LGTM!

Proper password verification with strict equality check.


37-58: LGTM!

Token generation flow is correct: builds payload, computes permissions via AbilityFactory, and signs JWT with 1-hour expiry. The short expiry is mitigated by ignoreExpiration in development mode (see jwt.strategy.ts line 18).

apps/api/src/users/users.service.ts (2)

1-1: LGTM!

Import reorganization moves accessibleQuery to local auth utilities while retaining other libnest imports.

Also applies to: 5-5


127-142: LGTM!

The includeHashedPassword option is correctly implemented. When true, the hashed password is included; when false or undefined, it's omitted. This supports the auth service's need to verify passwords during login.

apps/api/src/auth/strategies/jwt.strategy.ts (2)

11-22: LGTM!

JWT strategy configuration is correct. Ignoring expiration in development mode is a reasonable development convenience. Using getOrThrow for SECRET_KEY ensures fail-fast behavior.


24-27: LGTM!

The validate method correctly reconstructs the AppAbility from JWT permissions and enriches the payload. This integrates properly with the login flow in auth.service.ts where permissions are computed and embedded in the token.

apps/api/package.json (1)

18-22: LGTM! Dependencies properly updated for JWT/CASL authentication.

The dependency additions align well with the authentication refactor:

  • CASL packages for authorization
  • NestJS auth packages for JWT strategy
  • Passport packages for authentication middleware
  • Libnest v8 upgrade supports the new architecture

Also applies to: 29-30, 47-48, 57-59

testing/e2e/src/global/global.setup.spec.ts (1)

1-1: LGTM! Test updates align with new authentication system.

The changes improve test clarity and coverage:

  • Updated type import to $LoginCredentials from schemas
  • Improved test descriptions
  • Added security-focused tests (redirect to login, block duplicate setup)

Also applies to: 8-31, 34-45

apps/api/src/auth/ability.factory.ts (1)

56-62: LGTM! Clean delegation to utility function.

apps/api/src/auth/ability.utils.ts (3)

13-18: LGTM! Subject detection properly handles Prisma models.


20-24: LGTM! Ability creation properly configured.


26-35: No security issue found—ability is always passed from authenticated routes.

Verification confirms all accessibleQuery calls in protected routes receive ability from the @CurrentUser('ability') decorator. Every controller method is decorated with @RouteAccess, ensuring authentication enforcement, and explicitly passes the injected ability to service methods. The undefined case returns {} as intentional defensive design for flexibility (tested behavior), not a vulnerability in protected contexts.

apps/api/src/auth/guards/__tests__/jwt-auth.guard.spec.ts (2)

16-20: LGTM! Mock setup is correct.

Note: The Biome warning about shadowing "constructor" is a false positive in this hoisted mock context.


24-131: LGTM! Comprehensive test coverage.

The test suite thoroughly covers:

  • Public route access
  • Missing route metadata error handling
  • Authentication failures
  • Missing ability error handling
  • Permission validation (single and multiple permissions)
apps/api/src/core/decorators/route-access.decorator.ts (1)

1-22: LGTM! Clean decorator implementation with well-defined types.

The RouteAccess decorator properly integrates with NestJS metadata system for authorization.

apps/api/src/auth/auth.types.ts (1)

1-23: LGTM! Type definitions properly integrate CASL with Prisma.

The types leverage Prisma.TypeMap for type-safe authorization across all models.

apps/api/src/auth/guards/jwt-auth.guard.ts (1)

12-56: LGTM! Robust guard implementation with proper security checks.

The guard correctly:

  • Validates route metadata exists
  • Handles public routes without authentication
  • Ensures ability is present and valid before permission checks
  • Supports both single and multiple permission requirements
apps/api/src/instrument-records/instrument-records.controller.ts (4)

3-15: LGTM!

Import migration from DTOs to zod schema types is clean and consistent with the PR objective.


27-27: LGTM!

Schema type correctly replaces DTO.


34-34: LGTM!

Schema type correctly replaces DTO.


90-90: LGTM!

Schema type correctly replaces DTO with proper destructuring.

apps/api/src/core/prisma.ts (4)

16-33: LGTM!

Environment-aware connection logic is clean, and omitting hashedPassword from queries is a good security practice.


35-39: LGTM!

Shutdown logic is correct, assuming the assignment bug in createMemoryConnection() is fixed.


48-64: LGTM!

Connection string construction correctly filters empty params and builds environment-specific database name.


67-77: LGTM!

Type utilities correctly extract the extended client type and where-input mappings for type-safe Prisma queries.

Comment on lines +22 to +46
switch (payload.basePermissionLevel) {
case 'ADMIN':
ability.can('manage', 'all');
break;
case 'GROUP_MANAGER':
ability.can('manage', 'Assignment', { groupId: { in: groupIds } });
ability.can('manage', 'Group', { id: { in: groupIds } });
ability.can('read', 'Instrument');
ability.can('create', 'InstrumentRecord');
ability.can('read', 'InstrumentRecord', { groupId: { in: groupIds } });
ability.can('create', 'Session');
ability.can('read', 'Session', { groupId: { in: groupIds } });
ability.can('create', 'Subject');
ability.can('read', 'Subject', { groupIds: { hasSome: groupIds } });
ability.can('read', 'User', { groupIds: { hasSome: groupIds } });
break;
case 'STANDARD':
ability.can('read', 'Group', { id: { in: groupIds } });
ability.can('read', 'Instrument');
ability.can('create', 'InstrumentRecord');
ability.can('read', 'Session', { groupId: { in: groupIds } });
ability.can('create', 'Session');
ability.can('create', 'Subject');
ability.can('read', 'Subject', { groupIds: { hasSome: groupIds } });
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that create permissions for InstrumentRecord, Session, and Subject are properly scoped at the service layer.

The permission rules allow GROUP_MANAGER and STANDARD users to create records without explicit ability-level constraints on which groups they can create for. Ensure that service methods enforce group membership checks when creating these entities.


🏁 Script executed:

#!/bin/bash
# Verify that create methods in services enforce group scoping

echo "=== Checking InstrumentRecords Service ==="
rg -A 10 -B 2 'create.*InstrumentRecord' --type=ts apps/api/src/instrument-records/

echo -e "\n=== Checking Sessions Service ==="
rg -A 10 -B 2 'create.*Session' --type=ts apps/api/src/sessions/

echo -e "\n=== Checking Subjects Service ==="
rg -A 10 -B 2 'create.*Subject' --type=ts apps/api/src/subjects/

Length of output: 8128



🏁 Script executed:

#!/bin/bash
# Find @RouteAccess decorator implementation and Sessions/InstrumentRecords create implementations

echo "=== Finding @RouteAccess decorator ==="
fd -t f '@RouteAccess' --type ts apps/api/src/ || rg -l '@RouteAccess' apps/api/src/ --type ts | head -5

echo -e "\n=== Checking for RouteAccess decorator definition ==="
rg -A 5 -B 2 'RouteAccess.*decorator\|export.*RouteAccess' --type=ts apps/api/src/

echo -e "\n=== Sessions service.create full implementation ==="
rg -A 30 'async create\(' apps/api/src/sessions/sessions.service.ts

echo -e "\n=== InstrumentRecords service.create full implementation ==="
rg -A 30 'async create\(' apps/api/src/instrument-records/instrument-records.service.ts

Length of output: 2843



🏁 Script executed:

#!/bin/bash
# Verify groupsService.findById and Sessions controller behavior

echo "=== GroupsService.findById implementation ==="
rg -A 15 'async findById\(' apps/api/src/groups/groups.service.ts

echo -e "\n=== Sessions controller.create full method ==="
rg -B 5 -A 10 'create\(@Body\(\)' apps/api/src/sessions/sessions.controller.ts

echo -e "\n=== Search for RouteAccess definition ==="
rg 'export.*RouteAccess\|function RouteAccess' apps/api/src/ -A 3

Length of output: 1017



🏁 Script executed:

#!/bin/bash
# Final verification: check Subjects controller and RouteAccess type

echo "=== Subjects controller.create method ==="
rg -B 3 -A 8 '@RouteAccess.*Subject' apps/api/src/subjects/subjects.controller.ts | grep -A 8 'create\('

echo -e "\n=== RouteAccess in common/auth or shared ==="
find apps/api/src -name '*.ts' -exec grep -l 'export.*RouteAccess\|RouteAccess.*=' {} \; 2>/dev/null | head -3

echo -e "\n=== Check RouteAccess import source ==="
rg 'import.*RouteAccess' apps/api/src/sessions/sessions.controller.ts

Length of output: 337



🏁 Script executed:

#!/bin/bash
# Check RouteAccess decorator implementation and Subjects controller

echo "=== RouteAccess decorator implementation ==="
cat apps/api/src/core/decorators/route-access.decorator.ts

echo -e "\n=== Subjects controller.create full method ==="
rg -B 2 -A 12 'create\(@Body' apps/api/src/subjects/subjects.controller.ts

Length of output: 1348



🏁 Script executed:

#!/bin/bash
# Check Subjects service create method (not createMany)

echo "=== Subjects service.create implementation ==="
rg -A 20 'async create\(' apps/api/src/subjects/subjects.service.ts | head -30

Length of output: 647


Authorization bypass in Sessions and Subjects create endpoints.

Verification confirms the original concern: Session and Subject create operations bypass authorization checks.

  • Sessions: Controller doesn't pass ability to service; service calls groupsService.findById(groupId) without ability, allowing any user to create sessions for any group.
  • Subjects: Controller doesn't pass ability to service; service.create() doesn't use accessibleQuery at all, allowing any user to create subjects.
  • InstrumentRecords: Properly scoped—controller passes ability through the service chain and checks group access.

Both Sessions and Subjects endpoints need ability enforcement at the service layer, following the InstrumentRecords pattern: pass ability from controller and use accessibleQuery in service create methods.

Comment on lines +41 to +46
private async createMemoryConnection(): Promise<string> {
// prevent mongodb-memory-server from being included in the production bundle
const { MongoMemoryReplSet } = await import('mongodb-memory-server');
const replSet = await MongoMemoryReplSet.create({ replSet: { count: 1, name: 'rs0' } });
return new URL(replSet.getUri('test')).href;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Memory leak: replSet not stored for cleanup.

The MongoMemoryReplSet instance is created but not assigned to this.memoryReplSet, so onApplicationShutdown() cannot stop it, causing a resource leak.

Apply this diff:

   private async createMemoryConnection(): Promise<string> {
     // prevent mongodb-memory-server from being included in the production bundle
     const { MongoMemoryReplSet } = await import('mongodb-memory-server');
-    const replSet = await MongoMemoryReplSet.create({ replSet: { count: 1, name: 'rs0' } });
-    return new URL(replSet.getUri('test')).href;
+    this.memoryReplSet = await MongoMemoryReplSet.create({ replSet: { count: 1, name: 'rs0' } });
+    return new URL(this.memoryReplSet.getUri('test')).href;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private async createMemoryConnection(): Promise<string> {
// prevent mongodb-memory-server from being included in the production bundle
const { MongoMemoryReplSet } = await import('mongodb-memory-server');
const replSet = await MongoMemoryReplSet.create({ replSet: { count: 1, name: 'rs0' } });
return new URL(replSet.getUri('test')).href;
}
private async createMemoryConnection(): Promise<string> {
// prevent mongodb-memory-server from being included in the production bundle
const { MongoMemoryReplSet } = await import('mongodb-memory-server');
this.memoryReplSet = await MongoMemoryReplSet.create({ replSet: { count: 1, name: 'rs0' } });
return new URL(this.memoryReplSet.getUri('test')).href;
}
🤖 Prompt for AI Agents
In apps/api/src/core/prisma.ts around lines 41 to 46, the MongoMemoryReplSet
created in createMemoryConnection() is not assigned to this.memoryReplSet so
onApplicationShutdown() cannot stop it; assign the created replSet to
this.memoryReplSet (this.memoryReplSet = replSet) before returning the URI so
the instance can be cleaned up, and ensure the class has a matching
memoryReplSet property declaration if not already present.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
testing/e2e/playwright.config.ts (1)

75-76: Good addition for CI visibility.

Piping stderr unconditionally and stdout only in CI strikes the right balance between local dev silence and CI diagnostics.

If you'd like to reduce the duplication, consider extracting the pattern:

+const webServerStreams = {
+  stderr: 'pipe' as const,
+  stdout: (process.env.CI ? 'pipe' : 'ignore') as const
+};
+
 export default defineConfig({

Then reference it in each webServer:

     {
       command: 'pnpm dev:test',
       cwd: path.resolve(import.meta.dirname, '../../apps/api'),
       gracefulShutdown: {
         signal: 'SIGINT',
         timeout: 1000
       },
-      stderr: 'pipe',
-      stdout: process.env.CI ? 'pipe' : 'ignore',
+      ...webServerStreams,
       timeout: 10_000,
       url: `http://localhost:${apiPort}`
     },

Also applies to: 87-88, 99-100

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ca6d83 and c6c45c8.

📒 Files selected for processing (3)
  • packages/runtime-core/src/define.ts (2 hunks)
  • packages/runtime-core/src/types/instrument.series.ts (1 hunks)
  • testing/e2e/playwright.config.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/runtime-core/src/define.ts (3)
packages/runtime-core/src/types/instrument.base.ts (1)
  • InstrumentLanguage (223-223)
vendor/[email protected]/src/v3.d.ts (1)
  • Omit (820-820)
packages/runtime-core/src/types/instrument.series.ts (1)
  • SeriesInstrument (22-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: lint-and-test
🔇 Additional comments (3)
packages/runtime-core/src/types/instrument.series.ts (1)

6-6: LGTM! API promotion is clear.

Promoting SeriesInstrument from @beta to @public aligns with the new defineSeriesInstrument helper in define.ts.

packages/runtime-core/src/define.ts (2)

8-8: LGTM!

Import supports the new defineSeriesInstrument helper.


65-72: LGTM! Pattern matches defineInstrument.

The function correctly applies the same __runtimeVersion: 1 pattern used by defineInstrument. TypeScript enforces kind: 'SERIES' via the SeriesInstrument type constraint.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/playground/src/components/Header/LoginForm/LoginForm.tsx (1)

1-1: Consider UX-driven ordering or inline disable.

The eslint disable suggests the object properties don't follow project sorting conventions. If the current order (username before password) is intentional for UX, consider adding a comment explaining this. Otherwise, sort properties alphabetically and remove the disable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0639d84 and 57ebc73.

📒 Files selected for processing (10)
  • apps/api/libnest.config.ts (1 hunks)
  • apps/api/src/auth/auth.controller.ts (1 hunks)
  • apps/api/src/auth/auth.service.ts (1 hunks)
  • apps/api/src/typings/global.d.ts (1 hunks)
  • apps/playground/src/components/Header/LoginForm/LoginForm.tsx (1 hunks)
  • apps/playground/src/components/Header/LoginForm/index.ts (1 hunks)
  • apps/playground/src/store/index.ts (2 hunks)
  • apps/playground/src/store/slices/auth.slice.ts (1 hunks)
  • apps/playground/src/store/types.ts (2 hunks)
  • packages/schemas/src/auth/auth.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/api/libnest.config.ts
  • apps/api/src/typings/global.d.ts
  • apps/api/src/auth/auth.service.ts
🧰 Additional context used
🧬 Code graph analysis (5)
apps/playground/src/components/Header/LoginForm/LoginForm.tsx (1)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/playground/src/store/slices/auth.slice.ts (1)
apps/playground/src/store/types.ts (2)
  • SliceCreator (87-92)
  • AuthSlice (37-40)
apps/api/src/auth/auth.controller.ts (3)
apps/api/src/core/decorators/route-access.decorator.ts (1)
  • RouteAccess (18-20)
apps/api/libnest.config.ts (1)
  • RequestUser (21-23)
packages/schemas/src/auth/auth.ts (2)
  • $LoginCredentials (11-11)
  • $LoginCredentials (12-15)
apps/playground/src/store/index.ts (1)
apps/playground/src/store/slices/auth.slice.ts (1)
  • createAuthSlice (3-10)
packages/schemas/src/auth/auth.ts (1)
packages/schemas/src/core/core.ts (1)
  • Permissions (33-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: lint-and-test
🔇 Additional comments (9)
packages/schemas/src/auth/auth.ts (2)

11-15: LGTM! Non-empty string validation added.

The .min(1) validation on username and password fields prevents empty string submissions, improving input validation.


18-18: LGTM! Additional permissions field added.

The optional additionalPermissions field extends the token payload capabilities without breaking changes.

apps/api/src/auth/auth.controller.ts (1)

15-20: LGTM! Protected endpoint with proper authorization.

The endpoint correctly delegates to the service layer and enforces permission checks via RouteAccess.

apps/playground/src/components/Header/LoginForm/LoginForm.tsx (1)

10-30: LGTM! Simple and effective form implementation.

The component correctly uses the $LoginCredentials schema for validation and delegates submission handling to the parent via the onSubmit prop.

apps/playground/src/store/index.ts (2)

9-9: LGTM: Auth slice import follows existing pattern.

The import is correctly placed alongside other slice imports.


23-23: Add token lifecycle management; currently missing.

Verification confirms token handling is incomplete. The auth slice only stores and sets the token—there's no expiration tracking, refresh mechanism, or validation. Tokens are used directly in API calls without safeguards. Implement:

  • Token expiration detection and refresh flow
  • API interceptor to inject/validate tokens and handle 401 responses
  • Optional: Route guards to prevent navigation with expired tokens
apps/playground/src/store/slices/auth.slice.ts (1)

1-10: LGTM: Auth slice implementation is correct.

The slice follows Zustand + immer patterns correctly. The minimal implementation (just token storage) is appropriate—business logic like validation and expiration should be handled by auth services or middleware.

apps/playground/src/store/types.ts (2)

37-40: LGTM: AuthSlice type is well-defined.

The type correctly allows null | string for accessToken, enabling token clearing on logout.


85-85: LGTM: AppStore properly extended with AuthSlice.

The type composition is correct and maintains type safety across all store slices.

Comment on lines +22 to +28
@ApiOperation({ summary: 'Login' })
@HttpCode(HttpStatus.OK)
@Post('login')
@RouteAccess('public')
async login(@Body() credentials: $LoginCredentials): Promise<{ accessToken: string }> {
return this.authService.login(credentials);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Consider rate limiting and enhance API documentation.

The login endpoint is publicly accessible and lacks visible rate limiting, making it vulnerable to brute-force attacks. Also consider documenting error responses (401, 400) using @ApiResponse decorators.

Verify rate limiting configuration:

If rate limiting isn't configured, consider adding it:

import { Throttle } from '@nestjs/throttler';

// Add above the login method:
@Throttle({ default: { limit: 5, ttl: 60000 } }) // 5 attempts per minute

🏁 Script executed:

#!/bin/bash
# Check if rate limiting is configured globally or on auth routes
rg -nP --type=ts -C5 'ThrottlerModule|RateLimit|@Throttle'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check app.module.ts for ThrottlerModule import
fd -t f "app.module.ts" --exec cat {}

# Check main.ts for global guards or rate limiting setup
fd -t f "main.ts" --exec cat {}

# Search for any throttler-related imports in the codebase
rg -n "throttler|rate.limit" -i --type=ts

Length of output: 6568


Rate limiting is not configured. Add throttling to the login endpoint to prevent brute-force attacks.

Verification confirms no rate limiting is configured globally or on the auth routes. The login endpoint remains unprotected.

Add the @Throttle() decorator from @nestjs/throttler above the login method:

@Throttle({ default: { limit: 5, ttl: 60000 } })

Also document error responses using @ApiResponse decorators for 401 and 400 status codes.

🤖 Prompt for AI Agents
In apps/api/src/auth/auth.controller.ts around lines 22 to 28, the login
endpoint lacks rate limiting and response documentation; add the Throttle
decorator from @nestjs/throttler directly above the login method with the
provided settings (limit 5, ttl 60000) and add @ApiResponse decorators for 401
(Unauthorized) and 400 (Bad Request) to document error responses; also update
imports to include Throttle from @nestjs/throttler and ApiResponse from
@nestjs/swagger, placing the decorators immediately above the method signature
so Nest registers throttling and Swagger documents the error responses.

@joshunrau joshunrau merged commit f7c73d8 into DouglasNeuroInformatics:main Nov 19, 2025
1 check failed
@joshunrau joshunrau deleted the libnest-v8 branch November 19, 2025 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant